/*
 * Copyright 2009 Armando Blancas
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package tests.taskgraph.tasks.io;

import java.io.IOException;
import java.text.ParseException;

import junit.framework.Assert;
import junit.framework.JUnit4TestAdapter;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import taskgraph.channels.Channel;
import taskgraph.ports.InputPort;
import taskgraph.ports.OutputPort;
import taskgraph.tasks.io.JDBCResultSet;

public class JDBCResultSetTest {

	/**
	 * Runs the test suite in this class from the command line.
	 * 
	 * @param args	Arguments are ignored.
	 */
	public static void main(String[] args) {
		org.junit.runner.JUnitCore.runClasses(JDBCResultSetTest.class);
	}
	
	/**
	 * Provides compatibility with 3.x versions of JUnit.
	 * 
	 * @return A 3.x-compatible test suite.
	 */
	public static junit.framework.Test suite() {
		return new JUnit4TestAdapter(JDBCResultSetTest.class);
	}

	private static final String DATABASE_URL = "jdbc:mysql://localhost/books";

	private OutputPort<BookTitle> output;
	
	@Before
	public void setup() {
		Channel<BookTitle> channel = new Channel<BookTitle>();
		output = channel.getOutputPort();
	}
	
	@After
	public void cleanup() {
		output.close();
	}
	
    /*+----------------------------------------------------------------------+
	  |                                                                      | 
	  | Test the constructors.                                               | 
	  |                                                                      | 
	  +----------------------------------------------------------------------+*/
	
	@Test
	public void defaultConstructor() {
		JDBCResultSet<BookTitle> task = 
			new JDBCResultSet<BookTitle>();
		
		Assert.assertNotNull(task);
	}
	
	@Test
	public void defaultInstanceClass() {
		JDBCResultSet<BookTitle> task = 
			new JDBCResultSet<BookTitle>();
		
		Assert.assertEquals(JDBCResultSet.class, task.getClass());
	}

	@Test
	public void constructorWithArgs() {
		JDBCResultSet<BookTitle> task = 
			new JDBCResultSet<BookTitle>(output, BookTitle.class, "url", "stmt");
		
		Assert.assertNotNull(task);
	}
	
	@Test
	public void instanceClassWithArgs() {
		JDBCResultSet<BookTitle> task = 
			new JDBCResultSet<BookTitle>(output, BookTitle.class, "url", "stmt");
		
		Assert.assertEquals(JDBCResultSet.class, task.getClass());
	}

	@Test
	public void constructorWithFullArgs() {
		JDBCResultSet<BookTitle> task = 
			new JDBCResultSet<BookTitle>(
					output, BookTitle.class, "url", "user", "pwd", "stmt");
		
		Assert.assertNotNull(task);
	}
	
	@Test
	public void instanceClassWithFullArgs() {
		JDBCResultSet<BookTitle> task = 
			new JDBCResultSet<BookTitle>(
					output, BookTitle.class, "url", "user", "pwd", "stmt");
		
		Assert.assertEquals(JDBCResultSet.class, task.getClass());
	}

    /*+----------------------------------------------------------------------+
	  |                                                                      | 
	  | Test the run method with:                                            | 
	  |     Class: BookTitle.java                                            | 
	  |            Fields in this class are named after column names.        |
	  |     Table: books.Titles                                              | 
	  |                                                                      | 
	  +----------------------------------------------------------------------+*/
	
	@Test
	public void testRunWithOneBookTitle() throws IOException, ParseException {
		BookTitle expected = 
			new BookTitle("0131857576", "C++ How to Program", 5, "2005");

		Channel<BookTitle> ch = new Channel<BookTitle>();
		JDBCResultSet<BookTitle> task = 
			new JDBCResultSet<BookTitle>(
				ch.getOutputPort(), BookTitle.class, 
				DATABASE_URL, "dataflow", "dataflow", 
				"SELECT ISBN, Title, EditionNumber, Copyright " + 
				"FROM Titles " +
				"WHERE ISBN = '0131857576'");
		
		task.run();

		InputPort<BookTitle> input = ch.getInputPort();		
		BookTitle actual = input.read();
		input.close();

		Assert.assertEquals(expected.getISBN(),          actual.getISBN());
		Assert.assertEquals(expected.getTitle(),         actual.getTitle());
		Assert.assertEquals(expected.getEditionNumber(), actual.getEditionNumber());
		Assert.assertEquals(expected.getCopyright(),     actual.getCopyright());
	}

	@Test
	public void testRunWithBookTitles() throws IOException, ParseException {
		BookTitle[] titles = {
			new BookTitle("0131450913", "Internet & World Wide Web How to Program", 3, "2004"),
			new BookTitle("0131525239", "Visual C# 2005 How to Program", 2, "2006"),
			new BookTitle("0131828274", "Operating Systems", 3, "2004"),
			new BookTitle("0131857576", "C++ How to Program", 5, "2005"),
			new BookTitle("0131869000", "Visual Basic 2005 How to Program", 3, "2006"),
			new BookTitle("0132222205", "Java How to Program", 7, "2007"),
			new BookTitle("0132404168", "C How to Program", 5, "2007")
		};
			
		Channel<BookTitle> ch = new Channel<BookTitle>();
		JDBCResultSet<BookTitle> task = 
			new JDBCResultSet<BookTitle>(
				ch.getOutputPort(), BookTitle.class, 
				DATABASE_URL, "dataflow", "dataflow", 
				"SELECT ISBN, Title, EditionNumber, Copyright " + 
				"FROM Titles " +
				"ORDER BY ISBN ASC");
		
		task.run();

		InputPort<BookTitle> input = ch.getInputPort();		

		for (BookTitle expected : titles) {
			BookTitle actual = input.read();
			Assert.assertEquals(expected.getISBN(),          actual.getISBN());
			Assert.assertEquals(expected.getTitle(),         actual.getTitle());
			Assert.assertEquals(expected.getEditionNumber(), actual.getEditionNumber());
			Assert.assertEquals(expected.getCopyright(),     actual.getCopyright());
		}
		input.close();
	}

    /*+----------------------------------------------------------------------+
	  |                                                                      | 
	  | Test the run method with:                                            | 
	  |     Class: BookData.java                                             | 
	  |            Fields in this class are different from column names,     |
	  |            accessors are annotated with column names.                |
	  |     Table: books.Titles                                              | 
	  |                                                                      | 
	  +----------------------------------------------------------------------+*/
	
	@Test
	public void testRunWithBookData() throws IOException, ParseException {
		BookData[] titles = {
			new BookData("0131450913", "Internet & World Wide Web How to Program", 3, "2004"),
			new BookData("0131525239", "Visual C# 2005 How to Program", 2, "2006"),
			new BookData("0131828274", "Operating Systems", 3, "2004"),
			new BookData("0131857576", "C++ How to Program", 5, "2005"),
			new BookData("0131869000", "Visual Basic 2005 How to Program", 3, "2006"),
			new BookData("0132222205", "Java How to Program", 7, "2007"),
			new BookData("0132404168", "C How to Program", 5, "2007")
		};
			
		Channel<BookData> ch = new Channel<BookData>();
		JDBCResultSet<BookData> task = 
			new JDBCResultSet<BookData>(
				ch.getOutputPort(), BookData.class, 
				DATABASE_URL, "dataflow", "dataflow", 
				"SELECT ISBN, Title, EditionNumber, Copyright " + 
				"FROM Titles " +
				"ORDER BY ISBN ASC");
		
		task.run();

		InputPort<BookData> input = ch.getInputPort();		

		for (BookData expected : titles) {
			BookData actual = input.read();
			Assert.assertEquals(expected.getKey(),     actual.getKey());
			Assert.assertEquals(expected.getName(),    actual.getName());
			Assert.assertEquals(expected.getEdition(), actual.getEdition());
			Assert.assertEquals(expected.getNotice(),  actual.getNotice());
		}
		input.close();
	}

    /*+----------------------------------------------------------------------+
	  |                                                                      | 
	  | Negative tests for constructors.                                     | 
	  |                                                                      | 
	  +----------------------------------------------------------------------+*/

	@Test(expected=IllegalArgumentException.class)
	public void constructorWithNullOutputPort() throws IOException {
		new JDBCResultSet<BookTitle>(null, BookTitle.class, "url", "stmt");
	}

	@Test(expected=IllegalArgumentException.class)
	public void constructorWithNullClazz() throws IOException {
		new JDBCResultSet<BookTitle>(output, null, "url", "stmt");
	}

	@Test(expected=IllegalArgumentException.class)
	public void constructorWithNullURL() throws IOException {
		new JDBCResultSet<BookTitle>(output, BookTitle.class, null, "stmt");
	}

	@Test(expected=IllegalArgumentException.class)
	public void constructorWithNullStmt() throws IOException {
		new JDBCResultSet<BookTitle>(output, BookTitle.class, null, "stmt");
	}

	@Test(expected=IllegalArgumentException.class)
	public void constructor2WithNullOutputPort() throws IOException {
		new JDBCResultSet<BookTitle>(
			null, BookTitle.class, "user", "pwd", "url", "stmt");
	}

	@Test(expected=IllegalArgumentException.class)
	public void constructor2WithNullClazz() throws IOException {
		new JDBCResultSet<BookTitle>(
			output, null, "user", "pwd", "url", "stmt");
	}

	@Test(expected=IllegalArgumentException.class)
	public void constructor2WithNullURL() throws IOException {
		new JDBCResultSet<BookTitle>(
			output, BookTitle.class, null, "user", "pwd", "stmt");
	}

	@Test(expected=IllegalArgumentException.class)
	public void constructor2WithNullUser() throws IOException {
		new JDBCResultSet<BookTitle>(
			output, BookTitle.class, "url", null,  "pwd", "stmt");
	}

	@Test(expected=IllegalArgumentException.class)
	public void constructor2WithNullPwd() throws IOException {
		new JDBCResultSet<BookTitle>(
			output, BookTitle.class, "url", "user", null, "stmt");
	}

	@Test(expected=IllegalArgumentException.class)
	public void constructor2WithNullStmt() throws IOException {
		new JDBCResultSet<BookTitle>(
			output, BookTitle.class, "url", "user", "pwd", null);
	}

    /*+----------------------------------------------------------------------+
	  |                                                                      | 
	  | Negative tests.                                                      | 
	  |                                                                      | 
	  +----------------------------------------------------------------------+*/

}
